/*
 * @(#)ConnectorFactory.java   09/10/11
 * 
 * Copyright (C) 2009 Ecole des Mines d'Ales
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Contact: yulinz88@gmail.com
 */



package fr.ema.arch3d.ref.GenericFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;

import java.lang.reflect.Method;

//~--- classes ----------------------------------------------------------------

/**
 * Class description
 *
 *
 * @version        1.0, 09/09/13
 * @author         Huaxi (Yulin) ZHANG
 */
public class ConnectorFactory {

    /**
     * Method description
     *
     * @param connectorName  
     * @param ImplementedInterfaceName  
     * @return  
     * @throws ClassNotFoundException  
     * @throws IOException  
     */
    public String createConnectorImpl(String connectorName, String ImplementedInterfaceName)
            throws IOException, ClassNotFoundException {

        // get the interface class and methods
        Class  c      = Class.forName(ImplementedInterfaceName);
        Method meth[] = c.getMethods();

        // create connector implment file
        File   file;
        String name          = connectorName;
        String workspacePath = System.getProperty("user.dir");

        workspacePath = workspacePath.replace("\\", "//");

        String  path   = workspacePath + "//src//main//java//Example//Connectors//" + name + ".java";
        boolean exists = (new File(path)).exists();

        file = new File(path);

        // System.out.println(file.getAbsolutePath());
        boolean success = false;

        success = file.createNewFile();

        // write the file
        RandomAccessFile desc;

        desc = new RandomAccessFile(file, "rw");

        // add package
        desc.setLength(0);
        desc.writeBytes("package Example.Connectors;\n");
        desc.writeBytes("\n");

        // add imports
        desc.writeBytes("import java.util.HashMap;\n");
        desc.writeBytes("import java.util.Map;\n");
        desc.writeBytes("import org.objectweb.fractal.api.NoSuchInterfaceException;\n");
        desc.writeBytes("import org.objectweb.fractal.api.control.BindingController;\n");
        desc.writeBytes("import org.objectweb.fractal.api.control.IllegalBindingException;\n");
        desc.writeBytes("import org.objectweb.fractal.api.control.IllegalLifeCycleException;\n");

        // get the imports from the file of interfaces
        String         pathItf    = ImplementedInterfaceName.replace(".", "//");
        File           fileItf    = new File(workspacePath + "//src//main//java//" + pathItf + ".java");
        FileReader     fileReader = new FileReader(fileItf);
        BufferedReader reader     = new BufferedReader(fileReader);
        String         line       = "";

        while ((line = reader.readLine()) != null) {
            if (line.startsWith("import")) {
                if (!(line.equals("import java.util.HashMap;") || line.equals("import java.util.Map;")
                        || line.equals("import org.objectweb.fractal.api.NoSuchInterfaceException;")
                        || line.equals("import org.objectweb.fractal.api.control.BindingController;")
                        || line.equals("import org.objectweb.fractal.api.control.IllegalBindingException;")
                        || line.equals("import org.objectweb.fractal.api.control.IllegalLifeCycleException;"))) {
                    desc.writeBytes(line);
                }
            }
        }

        reader.close();
        desc.writeBytes("\n");

        // add imports interface
        desc.writeBytes("import " + ImplementedInterfaceName + ";\n");

        // begin class
        desc.writeBytes("public class " + name + " implements " + c.getSimpleName() + ", BindingController{\n");
        desc.writeBytes("\n");

        // declare fields
        desc.writeBytes("private Object service;\n");
        desc.writeBytes("private Map bindings = new HashMap();\n");
        desc.writeBytes("\n");

        // iml
        // listFc
        desc.writeBytes("public String[] listFc () {\n");
        desc.writeBytes("return (String[])bindings.keySet().toArray(new String[bindings.size()]);\n");
        desc.writeBytes("}\n");
        desc.writeBytes("\n");

        // lookupFc
        desc.writeBytes("public Object lookupFc (String itf) {\n");
        desc.writeBytes("return bindings.get(itf);\n");
        desc.writeBytes("}\n");
        desc.writeBytes("\n");

        // bindFc
        desc.writeBytes("public void bindFc (String itf, Object value) {\n");
        desc.writeBytes("if (!itf.equals(\"component\")) {\n");
        desc.writeBytes("bindings.put(itf, value);\n");
        desc.writeBytes("}\n");
        desc.writeBytes("}\n");
        desc.writeBytes("\n");

        // unbindFc
        desc.writeBytes(
            "public void unbindFc(String clientItfName) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {\n");
        desc.writeBytes("System.err.println(\"unbind\");\n");
        desc.writeBytes("if(!(bindings.get(clientItfName)==null))\n");
        desc.writeBytes("bindings.remove(clientItfName);\n");
        desc.writeBytes("}\n");

        // add methods of implemented interface
        // desc.writeBytes("ok"+(meth[0].getParameterTypes()).length);
        for (int i = 0; i < meth.length; i++) {
            desc.writeBytes("public ");
            desc.writeBytes(meth[i].getReturnType().getSimpleName() + " ");
            desc.writeBytes(meth[i].getName());

            int     len        = (meth[i].getParameterTypes()).length;
            boolean methodVoid = false;

            if (meth[i].getReturnType().getName() == "void") {
                methodVoid = true;
            }

            boolean methodException = false;
            String  exception       = null;

            if (meth[i].getExceptionTypes().length != 0) {
                exception       = " throws ";
                methodException = true;

                Class[] e = meth[i].getExceptionTypes();

                for (int k = 0; k < e.length; k++) {
                    exception = exception.concat(e[k].getSimpleName() + " ");
                }
            }

            if (len == 0) {
                desc.writeBytes("()");

                if (methodException) {
                    desc.writeBytes(exception);
                }

                desc.writeBytes("{\n");

                // desc.writeBytes("System.out.println(\"connector ok\");");
                if (methodVoid) {
                    desc.writeBytes("((");
                    desc.writeBytes(c.getSimpleName());
                    desc.writeBytes(") service).");
                    desc.writeBytes(meth[i].getName() + "()\n");
                    desc.writeBytes("}\n");
                } else {
                    desc.writeBytes("return ((");
                    desc.writeBytes(c.getSimpleName());
                    desc.writeBytes(") service).");
                    desc.writeBytes(meth[i].getName() + "()\n");
                    desc.writeBytes("}\n");
                }
            } else if (len > 0) {
                desc.writeBytes("(");

                for (int j = 0; j < len; j++) {
                    if (j < (len - 1)) {
                        desc.writeBytes(meth[i].getParameterTypes()[j].getSimpleName() + " a" + (j + 1) + ",");
                    }

                    if (j == (len - 1)) {
                        desc.writeBytes(meth[i].getParameterTypes()[j].getSimpleName() + " a" + (j + 1) + ")");
                    }
                }

                if (methodException) {
                    desc.writeBytes(exception);
                }

                desc.writeBytes("{\n");

                // desc.writeBytes("System.out.println(\"connector ok\");");
                if (methodVoid) {
                    desc.writeBytes("((");
                    desc.writeBytes(c.getSimpleName());
                    desc.writeBytes(") service).");
                    desc.writeBytes(meth[i].getName() + "(");

                    for (int k = 0; k < len; k++) {
                        if (k < (len - 1)) {
                            desc.writeBytes(" a" + (k + 1) + ",");
                        }

                        if (k == (len - 1)) {
                            desc.writeBytes(" a" + (k + 1) + ");");
                        }
                    }

                    desc.writeBytes("\n");
                    desc.writeBytes("}\n");
                } else {
                    desc.writeBytes("return ((");
                    desc.writeBytes(c.getSimpleName());
                    desc.writeBytes(") service).");
                    desc.writeBytes(meth[i].getName() + "(");

                    for (int k = 0; k < len; k++) {
                        if (k < (len - 1)) {
                            desc.writeBytes(" a" + (k + 1) + ",");
                        }

                        if (k == (len - 1)) {
                            desc.writeBytes(" a" + (k + 1) + ");");
                        }
                    }

                    desc.writeBytes("\n");
                    desc.writeBytes("}\n");
                }
            }

            desc.writeBytes("\n");
        }

        desc.writeBytes("}\n");

        return "Example.Connectors." + name;
    }
}
